#include <iostream>
#include <fstream>
#include <cstddef>
//#include <cmath>
//#include <allegro5/allegro.h>
//#include <allegro5/allegro_primitives.h>
#include <string>
#include <cstdio>
#include <sstream>
#include <limits>
#include "ServerSocket.h"
#include "SocketException.h"

using namespace std;

const int robotsNumber = 2;
const int mapLeft=100, mapTop=100, mapRight=900, mapBottom=900;
const int m=5, n=5, fieldSize=30;
//ALLEGRO_COLOR emptyColor, obstacleColor, gridColor, robotColor;

class Field;

enum FieldType {
    FT_EMPTY,
    FT_ROBOT,
    FT_OBSTACLE,
    FT_NONE
};

enum Direction {
    DIR_NORTH=8,
    DIR_SOUTH=2,
    DIR_WEST=4,
    DIR_EAST=6,
    DIR_NONE=5
};

enum CommandType {
    CMD_RBT_CHECK_MOVE,
    CMD_RBT_UPDATE,
    CMD_SRV_NEXT_TURN,
    CMD_SRV_CONNECTION_ESTABLISHED
};

void clearInput()
{
    std::cin.ignore(std::numeric_limits<streamsize>::max(),'\n');
}
class Robot{
public:
    static int newId;
    int id;
    Direction direction;
    Field* field;

//    void draw(int left, int top, float size)
//    {
//        al_draw_filled_circle(left+size/2,top+size/2,size/2,robotColor);
//        al_draw_circle(left+size/2,top+size/2,size/2,gridColor,1);
//        int directionX, directionY;
//        float half = size/2;
//        switch(direction){
//            case DIR_NORTH:
//                directionX=left+half;
//                directionY=top;
//                break;
//            case DIR_SOUTH:
//                directionX=left+half;
//                directionY=top+size;
//                break;
//            case DIR_WEST:
//                directionX=left;
//                directionY=top+half;
//                break;
//            case DIR_EAST:
//                directionX=left+size;
//                directionY=top+half;
//                break;
//        }
//        al_draw_line(left+half+0.5,top+half+0.5,directionX+0.5,directionY+0.5,gridColor,1);
//    }
    Robot() : id(newId), direction(DIR_NORTH), field(NULL)
    {
        newId++;
    }
};

int Robot::newId(0);

class Field{
public:
    FieldType content;
    Robot* robot;
    int x,y;

//    void draw(int left, int top, float size){
//        ALLEGRO_COLOR currentColor =(content==FT_OBSTACLE?obstacleColor:emptyColor);
//        al_draw_filled_rectangle(left,top,left+size,top+size,currentColor);
//        if(robot)
//        {
//            robot->draw(left,top,size);
//        }
//    }

    Field() : content(FT_EMPTY), robot(NULL) {}
};

class Map
{
public:
    int n,m;//n-liczba kolumn, m-liczba wierszy
    float fieldSize; //w cm
    Field **fields;

    FieldType checkMove(int x, int y, Direction direction) //zakladamy, ze pozycja x,y jest pozycja na planszy
    {
        switch(direction)
        {
            case DIR_NORTH:
                if(y>0){
                    return fields[y-1][x].content;
                }
                else{
                    return FT_NONE;
                }
                break;

            case DIR_SOUTH:
                if(y<m-1){
                    return fields[y+1][x].content;
                }
                else{
                    return FT_NONE;
                }
                break;

            case DIR_WEST:
                if(x>0){
                    return fields[y][x-1].content;
                }
                else{
                    return FT_NONE;
                }
                break;

            case DIR_EAST:
                if(x<n-1){
                    return fields[y][x+1].content;
                }
                else{
                    return FT_NONE;
                }
                break;

            case DIR_NONE:
                return fields[y][x].content;
        }
    }
    void moveRobot(Robot* robot, Direction direction)
    {
        if(robot && robot->field && direction!=DIR_NONE)
        {
            Field* field=robot->field;
            int x=field->x, y=field->y;
            FieldType fieldType = checkMove(x,y,direction);
            if(fieldType==FT_EMPTY)
            {
                fields[y][x].robot=NULL;
                fields[y][x].content=FT_EMPTY;
                switch(direction)
                {
                    case DIR_NORTH:
                        y=y-1;
                        break;

                    case DIR_SOUTH:
                        y=y+1;
                        break;

                    case DIR_WEST:
                        x=x-1;
                        break;

                    case DIR_EAST:
                        x=x+1;
                        break;
                }
                fields[y][x].robot=robot;
                fields[y][x].content=FT_ROBOT;
                robot->field=&fields[y][x];
                robot->direction=direction;
            }
        }
    }

    void putRobot(Robot* robot, int x, int y){
        if(fields[y][x].content==FT_EMPTY)
        {
            cout<<"Ustawiam robota na x: "<<x<<", y: "<<y<<endl;
            if(robot->field)
            {
                robot->field->robot=NULL;
                robot->field->content=FT_EMPTY;
            }
            robot->field=&fields[y][x];
            fields[y][x].robot=robot;
            fields[y][x].content=FT_ROBOT;
        }
        else
        {
            cout<<"Proba ustawienia robota na zajetym polu! Akcja przerwana.";
        }
    }

    Map(int _n, int _m, float _fieldSize) : n(_n), m(_m), fieldSize(_fieldSize)
    {
        fields = new Field*[m];
        for(int i=0;i<m;i++)
        {
            fields[i]=new Field[n];
            for(int j=0;j<n;j++)
            {
                fields[i][j].x=j;
                fields[i][j].y=i;
            }
        }
    }
    ~Map()
    {
        for(int i=0;i<m;i++)
        {
            delete[] fields[i];
        }
        delete[] fields;
    }

//    void draw(int left, int top, float size)
//    {
//        bool wider=true;
//        if(m>n)
//        {
//            wider=false;
//        }
//        float interval=(wider?size/n:size/m);
//        for(int i=0;i<m;i++)
//        {
//            for(int j=0;j<n;j++)
//            {
//                fields[i][j].draw(left+j*interval,top+i*interval,interval);
//            }
//        }
//        for(int i=0;i<=m;i++){
//            float y = top+i*interval+0.5;
//            al_draw_line(left,y,left+n*interval,y,gridColor,1);
//        }
//        for(int j=0;j<=n;j++){
//            float x = left+j*interval+0.5;
//            al_draw_line(x,top,x,top+m*interval,gridColor,1);
//        }
//    }
};

int main()
{
    char input;
//    al_init();
//    al_init_primitives_addon();
//    ALLEGRO_DISPLAY* display = al_create_display(900,900);

//    emptyColor=al_map_rgb(200,200,200);
//    obstacleColor=al_map_rgb(100,100,100);
//    gridColor=al_map_rgb(0,0,0);
//    robotColor=al_map_rgb(0,200,0);
//
//    al_clear_to_color(emptyColor);
//    al_draw_line(10,10,50,50,gridColor,1);
//    al_flip_display();

//    Map* map = new Map(n,m,fieldSize);
//    Robot* robots = new Robot[robotsNumber];
//    map->putRobot(&robots[0],0,0);
//    map->putRobot(&robots[1],n-1,m-1);
    bool end=false;

//    al_clear_to_color(al_map_rgb(100,0,0));
//    map->draw(mapLeft, mapTop, mapRight-mapLeft);
//    al_draw_line(10,10,1000,1000,al_map_rgb(255,255,255),3);
//    al_flip_display();

    try{

        //=====LOG===========
//        ofstream log;
//        string filename="";
//        cout<<"Podaj nazwe pliku do logowania (bez rozszerzenia): ";
//        cin>>filename;
//        filename.append(".txt");
//        log.open(filename.c_str());
        //===================

        ServerSocket server (30000);
        ServerSocket robotSockets[robotsNumber];
        int robotsConnected=0;
        while(robotsConnected<robotsNumber)
        {
            ServerSocket newSocket;
            server.accept(newSocket);
            cout<<"Nowe polaczenie.\n";
            string response,comm;
            newSocket << "hello\n";
            newSocket >>response;
            cout<<"resp: "<<response<<endl;

            newSocket<<"set_pos "<<10<<" "<<15<<"\n";
            //cin>>input;
            clearInput();
            do
            {
            	getline(cin,comm);
            	cin>>comm;
            	newSocket << comm;
            	newSocket >>response;
            	cout<<"resp: "<<response<<endl;
            }while(comm != "stop");


            /*cout<<"Wprowadz pozycje x robota: ";
            int x,y;
            cin>>x;
            cout<<"Wprowadz pozycje y robota: ";
            cin>>y;
            newSocket << x <<"\n"<< y<<"\n";*/

            robotSockets[robotsConnected]=newSocket;
            robotsConnected++;
        }
        int moves=0;
        const int totalMoves=10;

        while(moves<totalMoves)
        {
//            log << moves+1;
            for(int i=0;i<robotsNumber;i++)
            {
                ServerSocket& rs = robotSockets[i];
                rs << "next_turn"<<"\n";
                int command;
                bool end=false;
                while(!end)
                {
                    rs >> command;
                    if(command==CMD_RBT_CHECK_MOVE)
                    {
                        int direction;
                        rs >> direction;
//                        Field* field = robots[i].field;
//                        FieldType content = map->checkMove(field->x,field->y,(Direction)direction);
//                        rs << content<<"\n";
                    }
                    else if(command==CMD_RBT_UPDATE)
                    {

                    }

                }
//                Direction direction=DIR_NONE;
//                char c;
//                string s;
//                cin>>s;
//                c=s[0];
//                switch(c)
//                {
//                    case 'a':
//                        direction=DIR_WEST;
//                        break;
//
//                    case 'w':
//                        direction=DIR_NORTH;
//                        break;
//
//                    case 'd':
//                        direction=DIR_EAST;
//                        break;
//
//                    case 's':
//                        direction=DIR_SOUTH;
//                        break;
//                    default:
//                        direction=DIR_NONE;
//                }
//                map->moveRobot(&robots[i],direction);
//                map->draw(mapLeft, mapTop, mapRight-mapLeft);
//                al_flip_display();

            }
            moves++;
//            log<<endl;
        }
//        log<<"end";
//        log.close();
    }
    catch(SocketException& e)
    {
        cout<<"Blad polaczenia. Tresc bledu: "<<e.description()<<"\nZamykanie programu...";
    }

    cin>>input;
//    delete map;
//    delete[] robots;
//    al_shutdown_primitives_addon();
//    al_destroy_display(display);
//
    return 0;
}

//#include <cmath>
//#include "ViewPort.cpp"
//#include "Client.cpp"
//
//using namespace std;
//
//int main()
//{
//    al_set_new_display_flags(ALLEGRO_FULLSCREEN_WINDOW);
//    ALLEGRO_DISPLAY display = al_create_display(1000, 1000);
//    int displayWidth = al_get_display_width(display);
//    int displayHeight = al_get_display_height(display);
//
//    const int clientsCount =2;//, viewPortsCount = clientsCount+1, viewPortMargin=10;
//    int viewPortWidth =
//        (int)((displayWidth - (viewPortsCount+1)*viewPortMargin)/viewPortsCount);
//
//    ViewPort vp[viewPortsCount];
//    for(int i=0;i<viewPortsCount;i++)
//    {
//        vp[i].setPositionAndScale((i+1)*viewPortMargin+i*viewPortWidth,viewPortMargin,
//                       (i+1)*viewPortMargin+(i+1)*viewPortWidth,viewPortWidth+viewPortMargin);
//    }
//
//    Client clients[clientsCount];
//    for(int i=0;i<clientsCount;i++)
//    {
//        vp[0].addClient(&clients[i]);
//        vp[i+1].addClient(&clients[i]);
//    }
//
//
//    return 0;
//}
